package znet

import (
	"fmt"
	"net"
	"time"
	"zinx-study/utils"
	"zinx-study/ziface"
)

type Server struct {
	// Name 服务器名称
	Name string
	// IPVersion IP版本
	IPVersion string
	// IP IP地址
	IP string
	// Port 端口
	Port int
	// Router 路由，由用户绑定的回调Router，也就是Server注册的连接对应的处理业务
	//Router ziface.IRouter
	msgHandler ziface.IMsgHandle
}

func (s *Server) Start() {
	fmt.Printf("[START] Server name: %s,listenner at IP: %s, Port %d is starting\n", s.Name, s.IP, s.Port)
	fmt.Printf("[Zinx] Version: %s, MaxConn: %d,  MaxPacketSize: %d\n",
		utils.GObj.Version,
		utils.GObj.MaxConn,
		utils.GObj.MaxPacketSize)
	// 开启一个goroutine做服务端的Listener业务
	go func() {
		//0 启动worker工作池机制
		s.msgHandler.StartWorkerPool()
		//1 获取一个TCP的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("resolve tcp addr err: ", err)
			return
		}
		//2 获取一个TCP的Listener
		ln, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listen tcp addr err: ", err)
			return
		}
		fmt.Println("start Zinx server  ", s.Name, " succ, now listening...")

		//TODO server.go 应该有一个自动生成ID的方法
		var cid uint32
		cid = 0

		// 3 开始循环监听
		for {
			// 3.1 阻塞等待客户端建立TCP连接
			conn, err := ln.AcceptTCP()
			if err != nil {
				fmt.Println("accept tcp conn err: ", err)
				continue
			}
			// 3.2 TODO Server.Start() 设置服务器最大连接控制,如果超过最大连接，那么则关闭此新的连接

			// 3.3 处理该新连接请求的 业务 方法， 此时应该有 router 和 conn是绑定的
			dealConn := NewConnection(conn, cid, s.msgHandler)
			cid++
			go dealConn.Start()
		}
	}()
}

func (s *Server) Stop() {
	fmt.Println("[STOP] Zinx server , name ", s.Name)

	//TODO  Server.Stop() 将其他需要清理的连接信息或者其他信息 也要一并停止或者清理
}

func (s *Server) Serve() {
	s.Start()

	//TODO Server.Serve() 是否在启动服务的时候 还要处理其他的事情呢 可以在这里添加

	//阻塞,否则主Go退出， listenner的go将会退出
	for {
		time.Sleep(10 * time.Second)
	}
}

// AddRouter 路由功能：给当前服务注册一个路由业务方法，供客户端链接处理使用
func (s *Server) AddRouter(msgId uint32, router ziface.IRouter) {
	s.msgHandler.AddRouter(msgId, router)
}

// NewServer 创建一个服务器句柄
func NewServer() ziface.IServer {
	//先初始化全局配置文件
	utils.GObj.Load()
	s := &Server{
		Name:       utils.GObj.Name,
		IPVersion:  "tcp4",
		IP:         utils.GObj.Host,
		Port:       utils.GObj.TcpPort,
		msgHandler: NewMsgHandle(), //msgHandler 初始化
	}

	return s
}
